#include "ET++.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "StringGridView.h"

#include "Class.h"

#include "Math.h"
#include "Window.h"
#include "Look.h"
#include "Manager.h"
#include "TextView.h"

//---- CellEditField -----------------------------------------------------------

NewMetaImpl(CellEditField,EditField, (TP(sgridview), T(editcell)));

const char *CellEditField::GetStringForEditing()
{
	const char *s= sgridview->GetString(editcell, FALSE);
	if (s)
		return s;
	return "";
}

CellEditField::CellEditField(StringGridView *sgv, int minw, Font *f)
							: EditField(cIdNone, f->Width('w') * minw, f)
{
	sgridview= sgv;
	editcell= gPoint_1;
	SetFlag(eEditFieldNoBorder);
	SetContainer(sgridview);
}

bool CellEditField::ValidateString(const char *s)
{
	bool b= TRUE;
	const char *olds= sgridview->GetString(editcell, FALSE);
	if (olds == 0 || strcmp(s, (char*) olds) != 0)
		b= sgridview->SetString(editcell, s);
	if (b)
		editcell= gPoint_1;
	return b;
}

void CellEditField::SetEditCell(const Point &ec)
{
	Manager *m= GetManager();
	if (m) {
		editcell= ec;
		SetContentRect(sgridview->GetCellRect(editcell), TRUE);
		SetFont(sgridview->GetCellAttributes(editcell)->font);
		m->SetFirstHandler(this);
		UpdateEvent();
	}
}

Command *CellEditField::Input(Point lp, Token &t, Clipper *vf)
{
	if (t.IsKey() && t.Code == '\t') {
		sgridview->TabField(editcell, t);
		return gNoChanges;
	}
	return EditField::Input(lp, t, vf);
}

Command *CellEditField::InsertString(const char *s)
{
	TextViewOverlay *tv= GetTextViewOverlay();
	if (tv)
		return tv->GetOverlayTextView()->InsertString((const byte*)s);
	return gNoChanges;
}

//---- StringGridView ----------------------------------------------------------------

NewMetaImpl(StringGridView,GridView, (TP(tf)));

StringGridView::StringGridView(EvtHandler *eh, bool c) : GridView(eh, c)
{
	tf= new CellEditField(this, 10);
	modified= TRUE;
}

StringGridView::~StringGridView()
{
	SafeDelete(tf);
}

TextViewOverlay *StringGridView::GetTextViewOverlay()
{
	if (tf)
		return tf->GetTextViewOverlay();
	return 0;
}

const char *StringGridView::GetString(const Point&, bool)
{
	return 0;
}

bool StringGridView::SetString(const Point&, const char*)
{
	return FALSE;
}

Metric StringGridView::CellSize(const Point &cell)
{
	int b= (int)gLook->FieldBorderLayout(TRUE)->GetValue(this, 0);
	return StaticTextView::MeasureText(GetString(cell, TRUE),
		GetCellAttributes(cell)->font, 0, 1).Expand(gBorder+Point(b));
}

void StringGridView::DrawCell(const Point &cell, const Rectangle &r,
											const Rectangle &rr, bool highlight)
{
	if (tf && tf->editcell == cell) {
		tf->DrawAll(rr);
	} else {
		if (GrHasColor() && highlight)
			GrPaintRect(r, gHighlightColor);
		const char *s= GetString(cell, TRUE);
		if (s) {
			Rectangle rrr(r);
			CellAttributes *ca= GetCellAttributes(cell);
			int b= (int)gLook->FieldBorderLayout(TRUE)->GetValue(this, 0);
			StaticTextView::DrawBoxedText(rrr.Inset(gBorder+Point(b)), s,
						ca->font, ca->ink, FALSE, ca->align);
		}
		if (!GrHasColor() && highlight)
			GrPaintRect(r, gHighlightColor);
	}
}

bool StringGridView::SetEditCell(const Point &cell)
{
	Manager *m= GetManager();
	if (cell != tf->editcell) {
		if (m->SetFirstHandler(this)) {
			if (IsEditable(cell)) {
				if (!selection.ContainsPoint(cell))
					SetSelection(cell);
				tf->SetEditCell(cell);
				return TRUE;
			}
			return FALSE;
		}
		return FALSE;
	}
	return TRUE;
}

Point StringGridView::CalculateTab(const Point &curr, const Region &reg, bool fwd)
{
	Rectangle r(reg.BBox());
	Point p(curr);

	for (;;) {
		if (fwd) {
			if (p.y < r.origin.y+r.extent.y-1) {
				p.y++;
			} else {
				if (p.x < r.origin.x+r.extent.x-1) {
					p.x++;
					p.y= r.origin.y;
				} else
					p= r.origin;
			}
		} else {
			if (p.y > r.origin.y) {
				p.y--;
			} else {
				if (p.x > r.origin.x) {
					p.x--;
					p.y= r.origin.y+r.extent.y-1;
				} else
					p= r.SE();
			}
		}
		if (p == curr)
			break;
		if (reg.ContainsPoint(p) && IsEditable(p))
			break;
	}
	return p;
}

void StringGridView::TabField(const Point &cell, const Token &t)
{
	bool fwd= !(t.Flags & eFlgShiftKey);
	if (selection.BBox().origin == cell && selection.BBox().extent == gPoint1)
		SetEditCell(CalculateTab(cell, Rectangle(gPoint0, GetColsRows()), fwd));
	else
		SetEditCell(CalculateTab(cell, selection, fwd));
}

Command *StringGridView::DispatchEvents(Point lp, Token &t, Clipper *vf)
{
	Manager *m= GetManager();

	if (m) {
		Command *currCmd= 0;
		if (t.IsLeftClick() && !(t.Flags & eFlgShiftKey)) {
			if (m->SetFirstHandler(this)) {
				Point cell;
				PosToCell(lp, &cell);
				if (selection.ContainsPoint(cell) && SetEditCell(cell)) {
					if (currCmd= tf->Input(lp, t, vf))
						return currCmd;
				}
			}
		}
		if (t.IsKey() && selection.IsNotEmpty()) {
			Point p(CalculateTab(selection.BBox().origin, selection));
			//if (!IsEditable(p))
			//    p= CalculateTab(p, selection);
			if (SetEditCell(p)) {
				if (t.Code != '\t')
					if (currCmd= tf->Input(lp, t, vf))
						return currCmd;
			}
		}
	}
	return View::DispatchEvents(lp, t, vf);
}

void StringGridView::SetExtent(Point e)
{
	GridView::SetExtent(e);
	if (tf)
		tf->SetExtent(GetCellRect(tf->editcell).extent);
}

void StringGridView::SetOrigin(Point at)
{
	GridView::SetOrigin(at);
	if (tf)
		tf->SetOrigin(GetCellRect(tf->editcell).origin);
}

